package com.restkeeper.lock;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class CalculationBusinessLock{
    @Autowired
    private  RedisTemplate<String, Object> redisTemplate;

    private final String LOCKVALUE = "lockvalue";

    private boolean locked = false;

    //默认锁定超时时间
    private Integer lockTimeSecond= 10;



    /**
     * 自旋锁 是指当一个线程在获取锁的时候，如果锁已经被其它线程获取
     * 那么该线程将循环等待，然后不断的判断锁是否能够被成功获取，直到获取到锁才会退出循环。
     * 退出条件为估清剩余数目为0 和超时时间
     * @param lockKey
     * @param remainderCount 剩余数量计算逻辑
     * @return
     */
    public boolean spinLock(String lockKey, RemainderCount remainderCount){
        //如果没有获取到锁，循环获取
        while (!getLock(lockKey, lockTimeSecond)){
           // System.out.println("获取锁 "+lockKey+"  剩余数count :"+remainderCount.getRemainderCount());
            //如果剩余数为0，停止获取锁
            if(remainderCount.getRemainderCount()<=1) return false;
            //循环频率
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    /**
     * 普通锁
     * @param lockKey
     * @param lockTimeoutSeconds
     * @return
     */
    public boolean lock(String lockKey,Integer lockTimeoutSeconds){
        return getLock(lockKey,lockTimeoutSeconds);
    }


    private boolean getLock(String lockKey,int lockTimeoutSeconds){
        //设置锁，防止死锁，设置超时时间三秒
        Boolean success = redisTemplate.opsForValue().setIfAbsent(lockKey,LOCKVALUE);
        if(success != null && success){
            redisTemplate.expire(lockKey,lockTimeoutSeconds,TimeUnit.SECONDS);
            locked = true;
        }else{
            locked = false;
        }
        return locked;
    }

    /**
     * 释放锁
     * @param key
     */
    public void unlock(String key){
        redisTemplate.delete(key);
    }

    /*函数式接口
    我们常用的一些接口Callable、Runnable、Comparator等在JDK8中都添加了@FunctionalInterface注解。
		new Thread(()-> {
        System.out.println(Thread.currentThread().getName()+":使用lambda表达式创建线程");
    }).start();
    */
    @FunctionalInterface
    public interface RemainderCount{
        int getRemainderCount();
    }


}
